home *** CD-ROM | disk | FTP | other *** search
- /*----------------------------------------------------------
- #
- # NewsWatcher - Macintosh NNTP Client Application
- #
- # Written by Steven Falkenburg
- # ©1990 Apple Computer, Inc.
- #
- #-----------------------------------------------------------
- #
- # miscstuff.c
- #
- # This code module contains miscellaneous routines
- # called by many of the other code segments.
- # The memory management routines and status window
- # routines are contained in this module.
- #
- #-----------------------------------------------------------*/
-
- #include "compat.h"
- #include <stdlib.h>
- #include <CType.h>
- #include <string.h>
-
- #ifdef PROTOS
- #include <Types.h>
- #include <Memory.h>
- #include <QuickDraw.h>
- #include <Controls.h>
- #include <Dialogs.h>
- #include <OSUtils.h>
- #include <CursorCtl.h>
- #include <Strings.h>
- #include <OSEvents.h>
- #include <Windows.h>
- #include <Lists.h>
- #include <Fonts.h>
- #include <Packages.h>
- #include <Errors.h>
- #include <ErrMgr.h>
- #include <Desk.h>
- #endif
-
- #include "nntp.h"
- #include "miscstuff.h"
- #include "userint.h"
-
- #define kButtonFrameSize 3 /* button frameUs pen size */
- #define kButtonFrameInset 4 /*inset rectangle adjustment around button */
-
- static OSErr gMemError = noErr;
-
-
- #ifdef THINK_C
- void InitCursorCtl(long id)
- {
- }
-
- void SpinCursor(short num)
- {
- extern Cursor gWatchCurs;
- SetCursor(&gWatchCurs);
- }
- #endif
-
-
- /* OutlineOK: draws outline around ok button */
-
- void OutlineOK(DialogPtr theDialog)
- {
- short itemType;
- ControlHandle theItem;
- Rect itemRect;
- GrafPtr savePort;
- PenState thePen;
- short buttonOval;
-
- GetDItem(theDialog,okButton,&itemType,(Handle *)&theItem,&itemRect);
- GetPort(&savePort);
- GetPenState(&thePen);
- SetPort(theDialog);
- PenNormal();
- InsetRect(&itemRect,-kButtonFrameInset,-kButtonFrameInset);
- buttonOval = (itemRect.bottom-itemRect.top)/2;
- PenPat(QDBLACK);
- PenSize(kButtonFrameSize,kButtonFrameSize);
- FrameRoundRect(&itemRect,buttonOval,buttonOval);
- SetPenState(&thePen);
- SetPort(savePort);
- }
-
-
- /* CmdKeyFilter is used as a universal dialog box filter. It traps
- command-key events and checks for items which have the same first
- letter as the command key which was pressed. If a match is found,
- an event is generated for the appropriate item.
- */
-
- pascal Boolean CmdKeyFilter(DialogPtr theDialog,EventRecord *theEvent,short *itemHit)
- {
- char keyPressed;
- short itemNumber;
- short numItems;
- short iType;
- Handle iHndl;
- Rect iRect;
- Str255 btnTitle;
-
- /* totally convoluted and disgusting way to get the number of items in a dialog without
- using assembly-language crap or blockmove -- probably could be cleaner */
-
- numItems = (short) 1 + ((((char *)(*(((DialogPeek)theDialog)->items)))[0] << 8) + ((char *)(*(((DialogPeek)theDialog)->items)))[1]);
- keyPressed = theEvent->message & charCodeMask;
-
- if ((theEvent->what == keyDown) || (theEvent->what == autoKey)) {
- if ((keyPressed == CR) || (keyPressed == 03)) {
- *itemHit = okButton;
- return true;
- }
- if ((theEvent->modifiers & cmdKey) != 0) {
- if (keyPressed == '.') {
- *itemHit = cancelButton;
- return true;
- }
- else {
- for (itemNumber = 1;itemNumber <= numItems;itemNumber++) {
- GetDItem(theDialog,itemNumber,&iType,&iHndl,&iRect);
- if (iType == (ctrlItem+btnCtrl) || iType == (ctrlItem+chkCtrl) || iType == (ctrlItem+radCtrl)) {
- GetCTitle((ControlHandle)iHndl,btnTitle);
- if (toupper(btnTitle[1]) == toupper(keyPressed)) {
- *itemHit = itemNumber;
- return true;
- }
- }
- }
- }
- }
- }
- return false;
- }
-
-
- /* BlessedFolder returns the vRefNum of the currently active system folder.
- */
-
- short BlessedFolder(void)
- {
- SysEnvRec sysEnv;
-
- if (SysEnvirons(1,&sysEnv) != noErr)
- return 0;
- return (sysEnv.sysVRefNum);
- }
-
-
- /* GiveTime is called whenever the application is waiting for a slow
- process to complete. The routine calls SpinCursor and WaitNextEvent
- to give time to currently running background applications.
-
- This procedure can be thought of as a secondary main event loop.
- */
-
- Boolean GiveTime(unsigned long sleepTime)
- {
- EventRecord ev;
- static unsigned short count = 0;
- extern Boolean gInBackground;
- extern Boolean gCancel;
- extern Boolean gHasWaitNextEvent;
-
- Boolean gotEvt;
-
- if (gInBackground)
- sleepTime *= 5;
- else if ((count%6) == 0)
- SpinCursor(12);
-
- if ( (count%10) == 0 ) {
-
- if (gHasWaitNextEvent)
- gotEvt = WaitNextEvent(everyEvent,&ev,sleepTime,nil);
- else {
- gotEvt = GetNextEvent(everyEvent,&ev);
- SystemTask();
- }
-
- if ( gotEvt )
- switch (ev.what) {
- case mouseDown:
- if (IsMovableModal(FrontWindow()))
- HandleMouseDowns(&ev);
- break;
- case activateEvt:
- HandleActivates(&ev);
- break;
- case updateEvt:
- HandleUpdates((WindowPtr)(ev.message));
- break;
- case app4Evt:
- HandleSREvt(ev.message);
- break;
- case keyDown:
- case autoKey:
- FlushEvents(keyDownMask+keyUpMask+autoKeyMask,0);
- if ((ev.modifiers & cmdKey) != 0 && (ev.message & charCodeMask) == '.') {
- gCancel = true;
- }
- break;
- }
- }
-
- count++;
-
- return !gCancel;
- }
-
-
- /* StatusWindow displays a movable-modal status window indicating
- the current state of the program. An optional percent-complete
- status bar may also be displayed.
- */
-
- Boolean StatusWindow(char *text,short percent)
- {
- WindowPtr statusWind;
- Rect bounds = {0,0,60,230};
- extern short gMoveModalProc;
- TwindowInfo *info;
- Rect tmpRect;
- GrafPtr savePort;
- extern TPrefRec gPrefs;
- extern Rect desktopExtent;
-
- if (PtInRect(gPrefs.statusWindowLocn,&desktopExtent))
- OffsetRect(&bounds,gPrefs.statusWindowLocn.h,gPrefs.statusWindowLocn.v);
-
- if (!IsMovableModal(statusWind = FrontWindow())) {
- info = (TwindowInfo *) MyNewPtr(sizeof(TwindowInfo));
- if (MyMemErr() != noErr)
- return false;
- info->data2 = (unsigned long) MyNewPtr(256);
- if (MyMemErr() != noErr)
- return false;
- *((char *)info->data2) = 0;
- info->kind = cMoveModal;
- info->numGroups = -2;
- statusWind = NewWindow(nil,&bounds,"\pStatus",true,gMoveModalProc,(WindowPtr)-1,
- false,(unsigned long)info);
- }
- else info = (TwindowInfo *) GetWRefCon(statusWind);
-
- GetPort(&savePort);
- SetPort(statusWind);
-
- if (strcmp(text,(char *)info->data2) != 0) {
- strcpy((char *)info->data2,text);
- SetRect(&tmpRect,0,0,230,44);
- InvalRect(&tmpRect);
- }
- if (info->numGroups != percent) {
- info->numGroups = percent;
- SetRect(&tmpRect,0,45,230,60);
- InvalRect(&tmpRect);
- }
-
- if (info->numGroups <= 0)
- UpdateStatus();
-
-
- SetPort(savePort);
-
- return true;
- }
-
-
- /* UpdateStatus is called in response to update events for the status
- window. This routine will redraw sections of the window as necessary.
- */
-
- void UpdateStatus(void)
- {
- GrafPtr savePort;
- WindowPtr statusWind;
- TwindowInfo *info;
- short percent;
- Rect percentRect,tmpRect;
- short newRight;
-
- if (!FrontWindow()) {
- SysBeep(1);
- return;
- }
-
- info = (TwindowInfo *) GetWRefCon(statusWind = FrontWindow());
- percent = info->numGroups;
-
- if (!IsMovableModal(statusWind))
- return;
-
- GetPort(&savePort);
- SetPort(statusWind);
-
- tmpRect = statusWind->portRect;
- if (percent > 0)
- tmpRect.bottom = 35;
- EraseRect(&tmpRect);
-
- TextFont(systemFont);
- TextSize(12);
- MoveTo(20,30);
- DrawText((char *)info->data2,0,strlen((char *)info->data2));
- if (percent >= 0) {
- SetRect(&percentRect,20,45,210,55);
- FrameRect(&percentRect);
- InsetRect(&percentRect,1,1);
- newRight = percentRect.left + (short) (((float)(percentRect.right-percentRect.left))*((float)percent/100.0));
- if (newRight < percentRect.right)
- percentRect.right = newRight;
- FillRect(&percentRect,QDDKGRAY);
- }
- SetPort(savePort);
- }
-
-
- /* CloseStatusWindow is called when the status window should be removed.
- */
-
- void CloseStatusWindow(void)
- {
- WindowPtr statusWind;
- GrafPtr savePort;
- extern TPrefRec gPrefs;
- TwindowInfo *info;
-
- if (IsMovableModal(statusWind = FrontWindow())) {
- SetPt(&gPrefs.statusWindowLocn,0,0);
- GetPort(&savePort);
- SetPort(statusWind);
- LocalToGlobal(&gPrefs.statusWindowLocn);
-
- info = (TwindowInfo *)GetWRefCon(statusWind);
-
- SetPort(savePort);
- MyDisposPtr( (Ptr) (info->data2) );
- MyDisposPtr( (Ptr) info );
- DisposeWindow(statusWind);
- }
- }
-
-
- /* MyIOCheck can be called to display the result of a routine returning
- an OSErr. If the value in err is zero, the routine simply terminates.
- */
-
- OSErr MyIOCheck(OSErr err)
- {
- Str255 errNoStr;
-
- if (err != noErr) {
- NumToString(err,errNoStr);
- ParamText("\pAn error has occurred",errNoStr,"\p","\p");
- StopAlert(kErrDlg,nil);
- }
- return err;
- }
-
-
- /* LowMemory is called when the program runs out of useable memory.
- If this is the first time this has happened, the program de-allocates
- lifeboat memory which was allocated when the program was launched.
- Otherwise, the user had better quit.
- */
-
- Boolean LowMemory(void)
- {
- extern Handle gLifeBoat;
- extern Boolean gSinking;
- extern Boolean gOutOfMemory;
- Boolean result;
-
- if (MyMemErr() != memFullErr) {
- MyIOCheck(MyMemErr());
- return false;
- }
-
- if (gSinking) {
- result = false;
- gOutOfMemory = true;
- ParamText("\pYou have run out of memory","\p","\p","\p");
- }
- else {
- HUnlock(gLifeBoat);
- DisposHandle(gLifeBoat);
- gSinking = true;
- result = true;
- ParamText("\pMemory is getting low. Some operations may fail.","\p","\p","\p");
- }
- StopAlert(kErrDlg,nil);
- return result;
- }
-
-
- /* This is a wrapper for the NewPtr routine which automatically checks
- the result of the call and takes appropriate action.
- */
-
- Ptr MyNewPtr(Size byteCount)
- {
- Ptr thePtr;
-
- thePtr = NewPtr(byteCount);
- if ((gMemError = MemError()) != noErr) {
- if (LowMemory())
- thePtr = MyNewPtr(byteCount);
- else
- thePtr = nil;
- }
- return thePtr;
- }
-
-
- /* This is a wrapper for the NewHandle routine which automatically checks
- the result of the call and takes appropriate action.
- */
-
- Handle MyNewHandle(Size byteCount)
- {
- Handle theHndl;
-
- theHndl = NewHandle(byteCount);
- if ((gMemError = MemError()) != noErr) {
- if (LowMemory())
- theHndl = MyNewHandle(byteCount);
- else
- theHndl = nil;
- }
- return theHndl;
- }
-
- /* This is a wrapper for the SetHandleSize routine which automatically checks
- the result of the call and takes appropriate action.
- */
-
- void MySetHandleSize(Handle h,Size newSize)
- {
- SetHandleSize(h,newSize);
- if ((gMemError = MemError()) != noErr) {
- if (LowMemory())
- MySetHandleSize(h,newSize);
- }
- }
-
-
- /* This is a wrapper for the SetPtrSize routine which automatically checks
- the result of the call and takes appropriate action.
-
- Note: don't call SetPtrSize to increase allocation for a pointer!
- */
-
- void MySetPtrSize(Ptr p,Size newSize)
- {
- SetPtrSize(p,newSize);
- if ((gMemError = MemError()) != noErr) {
- if (LowMemory())
- MySetPtrSize(p,newSize);
- }
- }
-
-
- /* This is a wrapper for the HandToHand routine which automatically checks
- the result of the call and takes appropriate action.
- */
-
- OSErr MyHandToHand(Handle *theHndl)
- {
- Handle oldHndl;
- OSErr result;
-
- oldHndl = *theHndl;
- result = gMemError = HandToHand(theHndl);
- if (result != noErr) {
- *theHndl = oldHndl;
- if (LowMemory())
- MyHandToHand(theHndl);
- }
- return result;
- }
-
-
- /* This is a wrapper for the DisposPtr routine which automatically checks
- the result of the call and takes appropriate action.
- */
-
- OSErr MyDisposPtr(Ptr thePtr)
- {
- DisposPtr(thePtr);
- gMemError = MemError();
- return MyIOCheck(MemError());
- }
-
-
- /* This is a wrapper for the DisposHandle routine which automatically checks
- the result of the call and takes appropriate action.
- */
-
- OSErr MyDisposHandle(Handle theHndl)
- {
- DisposHandle(theHndl);
- gMemError = MemError();
- return MyIOCheck(MemError());
- }
-
-
- /* This is a wrapper for the MemError routine which automatically checks
- the result of the call and takes appropriate action.
- */
-
- OSErr MyMemErr(void)
- {
- return gMemError;
- }
-
-
- /* ReadPrefs reads the preferences file off of the disk file.
- The preferences are stored in a global block of memory.
- */
-
- OSErr ReadPrefs(TPrefPtr thePrefs)
- {
- OSErr err;
- short fRefNum;
- long count;
-
- if ((err = FSOpen(kPrefName,BlessedFolder(),&fRefNum))==noErr) {
- count=sizeof(TPrefRec);
- err = FSRead(fRefNum,&count,(Ptr)thePrefs);
- FSClose(fRefNum);
- }
- else {
- thePrefs->newsServerName[0] = '\0';
- thePrefs->mailServerName[0] = '\0';
- thePrefs->name[0] = '\0';
- thePrefs->host[0] = '\0';
- thePrefs->fullName[0] = '\0';
- thePrefs->organization[0] = '\0';
- thePrefs->signature[0] = '\0';
- thePrefs->address[0] = '\0';
-
- BlockMove("\pGeneva",thePrefs->listFont,7L);
- BlockMove("\pMonaco",thePrefs->textFont,7L);
- thePrefs->listSize = kListFontSize;
- thePrefs->textSize = kTextFontSize;
- SetRect(&thePrefs->groupWindowSize,4,40,300,340);
- SetPt(&thePrefs->windowOffset,10,30);
- SetPt(&thePrefs->statusWindowLocn,100,100);
- thePrefs->groupWindowVisible = true;
- thePrefs->openWindowsZoomed = false;
- thePrefs->parentWindows = true;
- thePrefs->mostRecentFirst = false;
- thePrefs->maxFetch = 400;
- }
- return noErr;
- }
-
-
- /* WritePrefs writes the NewsWatcher preferences back to the News Prefs
- file. This is called when the program terminates.
- */
-
- OSErr WritePrefs(TPrefPtr thePrefs)
- {
- OSErr err;
- short fRefNum;
- long count;
-
- if ((err = FSOpen(kPrefName,BlessedFolder(),&fRefNum))==fnfErr) {
- Create(kPrefName,BlessedFolder(),kFCreator,kPrefType);
- err = FSOpen(kPrefName,BlessedFolder(),&fRefNum);
- }
- if (err != noErr)
- return err;
-
- count=sizeof(TPrefRec);
- err = FSWrite(fRefNum,&count,(Ptr)thePrefs);
- FSClose(fRefNum);
- return err;
- }
-